package br.unisul.redeNeural;


/**
 * Classe especifica para configura uma Rede Neural Artificial {@link MLP}<br>
 * @author Joelson Fernandes
 *
 */
public class ConfiguracaoMLP implements FuncaoAtivacao, Atualizar<Vies>, CalculoSaida, VerificarSaida, java.io.Serializable{
	
	/**
	 * 
	 */
	private static final long serialVersionUID = -5634423784546119327L;
	
	private MLP mlp;
	
	/**
	 * @param mlp
	 */
	public ConfiguracaoMLP(MLP mlp) {
		super();
		this.mlp = mlp;
	}

	public double funcao(double x) {
		if (MLP.BINARIA == mlp.getTipo()) {
			return 1.0 / (1.0 + Math.exp(-1 * x));
		} else {
			return (2.0 / (1.0 + Math.exp(-1 * x))) - 1;
		}
	}
	
	public double atualizarValor(Vies entidade, Double valor) {
		if(entidade != null){
			entidade.setValor(valor);
			return valor;
		}
		return Integer.MIN_VALUE;
	}
	
	public double calcularSaidaNeuronio(Neuronio[] entradas,
			Peso[] pesos, Neuronio responsalvel) {

		if(entradas.length == pesos.length){
			double d = 0;
			for (int i = 0; i < pesos.length; i++) {
				d += entradas[i].getValorNeuronio() * pesos[i].getValor();
			}
			Vies v = responsalvel.getVies();
			if(v != null){
				d+= v.getValor();
			}
			d = mlp.aplicarFuncaoAtivacao(d);
			responsalvel.setValorNeuronio(d);
			return d;
		}
		return Integer.MIN_VALUE;
	}
	
	public double[] verificarSaidas(double[] entradas) throws RedeNeuralException {
		mlp.atualizarEntradas(entradas);
		for (int j = 1; j < mlp.quantidadeCamadas(); j++) {
			Neuronio neuroniosTemp[] = mlp.getNeuronios(j);
			for (int k = 0; k < neuroniosTemp.length ; k++) {
				Neuronio[] neuronios = mlp.getNeuroniosEntrada(j, k);
				Peso[] pesos = mlp.getPesosEntrada(j, k);
				mlp.calcularSaidaNeuronio(neuronios, pesos, neuroniosTemp[k]);
			}
		}
		
		Neuronio n[] = mlp.getSaidas();
		double d[] = new double[n.length];
		for (int i = 0; i < d.length; i++) {
			d[i] = n[i].getValorNeuronio();
		}
		return d;
	}

}
